package com.ktg.mes.unit.sync;


import com.alibaba.fastjson.JSONObject;
import com.ktg.common.utils.DateUtils;
import com.ktg.common.utils.StringUtils;
import com.ktg.mes.unit.sql.domain.MTableColumn;
import com.ktg.mes.unit.sql.domain.SQLCType;
import com.ktg.mes.unit.sql.domain.SQLDBConfig;
import com.ktg.mes.unit.sql.domain.SQLToolModel;
import com.ktg.mes.unit.sql.service.SQLToolService;
import com.ktg.mes.unit.sync.sql.SyncService;
import com.ktg.mes.webSocket.NoticeWbsocketType;
import com.ktg.mes.webSocket.NoticeWebsocket;
import lombok.EqualsAndHashCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;



@EqualsAndHashCode(callSuper = false)
public class SyncModel implements Serializable {

    private static final Logger log = LoggerFactory.getLogger(SyncModel.class);
    private SyncService fromIService;

    private SQLToolService toIService;

    private String fromTable;
    private String toTable;

    private Object moreThan = null;
    private String fromUpdateKey; // 根据更新字段
    private String toUpdateKey; //
    private String formOnlyKey; //来源表唯一标识
    private String toOnlyKey; //来源表唯一标识
    private List<String> fromColumnList;
    private List<String> toColumnList;


    private Map<String,Object> defaultValue = new HashMap<>();
    private List<SyncModelType> toColumnTypeList;

    private Map<String,Map> fromToChangeMap; // 值转换 如：1-男 2-女
    private Map<String,String > fromToChangeDefaultMap = new HashMap<>(); // 值转换 如：1-是，其他所有-否
    private int size = 300;



    public SyncModel setService(SyncService fromIService, SQLToolService toIService){
        this.fromIService = fromIService;
        this.toIService = toIService;
        return this;
    }

    public Map<String, MTableColumn> columnMap;
    public SyncModel setTable(String fromTable, String toTable){
        this.fromTable = fromTable;
        this.toTable = toTable;
        columnMap = toIService.getColumType(SQLDBConfig.master,toTable);
        return this;
    }

    public SyncModel setSyncData( String formOnlyKey,String fromUpdateKey,String toOnlyKey,String toUpdateKey){
        this.formOnlyKey = formOnlyKey;
        this.fromUpdateKey = fromUpdateKey;
        this.toOnlyKey = toOnlyKey;
        this.toUpdateKey = toUpdateKey;
        return this;
    }

    public SyncModel addColumn(String fromColumn, String toColumn, SyncModelType toColunmSyncModelType){
        if (fromColumnList == null){
            fromColumnList = new ArrayList<>();
        }
        if (toColumnList == null){
            toColumnList = new ArrayList<>();
        }
        if (toColumnTypeList == null){
            toColumnTypeList = new ArrayList<>();
        }
        fromColumnList.add(fromColumn);
        toColumnList.add(toColumn);
        toColumnTypeList.add(toColunmSyncModelType);
        return this;
    }

    public SyncModel putDefaultValue(String toColumn,Object obj){
        defaultValue.put(toColumn,obj);
        return this;
    }
    public SyncModel addColumn(String fromColumn, String toColumn, SyncModelType toColunmSyncModelType,Map itemFromToChangeMap,String defaultValue){
        if (fromColumnList == null){
            fromColumnList = new ArrayList<>();
        }
        if (toColumnList == null){
            toColumnList = new ArrayList<>();
        }
        if (toColumnTypeList == null){
            toColumnTypeList = new ArrayList<>();
        }
        fromColumnList.add(fromColumn);
        toColumnList.add(toColumn);
        toColumnTypeList.add(toColunmSyncModelType);
        if (this.fromToChangeMap == null){
            fromToChangeMap = new HashMap<>();
        }
        fromToChangeMap.put(toColumn,itemFromToChangeMap);
        if (defaultValue != null){
            fromToChangeDefaultMap.put(toColumn,defaultValue);
        }

        return this;
    }



    private int page = 0;
    public synchronized void synsStart(String title){
        page = 0;
        int count = 0;
        Object updateValue = this.getMoreThan();
        int allCount = 0;
        do {
            try{
                count = 0;
                // 查询来源数据库

                List<Map> list = getSelect(updateValue);
                // 跟新本地数据库
                for (int i = 0; i < list.size(); i++) {
                    if (this.fromUpdateKey != null){
                        updateValue = list.get(i).get(this.fromUpdateKey);
                    }else {
                        updateValue = list.get(i).get(this.formOnlyKey);
                    }
                    updateOrInsert(list.get(i));
                    allCount++;
                }
                page++;

                count = list.size();
                NoticeWebsocket.sendMessage(NoticeWbsocketType.SyncT6,title+"同步数据："+allCount);
            }catch (Exception e){
                e.printStackTrace();
            }
        }while (count == size);
        log.debug("更新完成：from:"+fromTable+" to:"+toTable+" 数量："+allCount);
    }


    public synchronized Object getMoreThan() {
        if (StringUtils.isEmpty(toUpdateKey)) {
            return moreThan;
        }else {
            String findSql = "select "+toUpdateKey+" from "+ toTable +" order by "+toUpdateKey+" desc limit 1";
            List<JSONObject> list = toIService.selectSqlMap(findSql);
            if (list != null && list.size() > 0 && list.get(0) != null && list.get(0).get(toUpdateKey) != null){
                return list.get(0).get(toUpdateKey);
            }
            return moreThan;
        }
    }


    public synchronized List<Map> getSelect(Object moreTh){
        SQLModel sqlModel = new SQLModel(fromTable);
        sqlModel.setSize(size);
        sqlModel.addColumns(formOnlyKey);

        try{
            for (int i = 0; i < toColumnList.size(); i++) {
                sqlModel.addColumnAs(fromColumnList.get(i),toColumnList.get(i));
            }

            if (moreTh != null){
                if (fromUpdateKey == null){
                    sqlModel.addWhere(formOnlyKey,">",moreTh);
                }else {
                    sqlModel.addWhere(fromUpdateKey,">",moreTh);
                }
            }

            if (this.fromUpdateKey != null){
                sqlModel.setOrderByColumn(this.fromUpdateKey);
            }else {
                sqlModel.setOrderByColumn(this.formOnlyKey);
            }

            List<Map> list = fromIService.selectSqlModel(sqlModel);
            return list;
        }catch (Exception e){
            log.error(sqlModel.toString());
            log.error("数据同步："+moreThan,e);
        }

        return null;
    }


    private String objectToStr(Object obj){
        if (obj instanceof String){
            return "'"+(String) obj+"'";
        }else {
            return String.valueOf(obj.toString());
        }
    }

    public synchronized void updateOrInsert(Map map){
        String onlyKey =  toOnlyKey;

        SQLToolModel find = new SQLToolModel(SQLDBConfig.master,toTable,columnMap);
        find.addColumns("count(0) as count");
        find.addWhere(onlyKey,map.get(onlyKey));
        List<JSONObject> one = toIService.selectSqlModel(find);


        SQLToolModel sqlModel = new SQLToolModel(SQLDBConfig.master,toTable, columnMap);

        if (one == null || one.size() == 0 || one.get(0).get("count").toString().equals("0")){
            for (int i = 0; i < toColumnList.size(); i++) {
                String column = toColumnList.get(i);
                if (this.defaultValue != null && this.defaultValue.size() > 0){
                    this.defaultValue.remove(column);
                }
                sqlModel.insertColumAndValue(column,map.get(column));
            }
            if (this.defaultValue != null && this.defaultValue.size() > 0){
                for (String key:this.defaultValue.keySet()) {
                    sqlModel.insertColumAndValue(key,defaultValue.get(key));
                }
            }
            toIService.insertModel(sqlModel);
        }else {
            for (int i = 0; i < toColumnList.size(); i++) {
                String column = toColumnList.get(i);
                Object val = map.get(column);
                if (!val.toString().equals("NULL")){
                    sqlModel.updateColumAndValue(column,map.get(column));
                }
            }
            sqlModel.addWhere(onlyKey,map.get(onlyKey));
            toIService.updateModel(sqlModel);
        }
    }


    public String getStringFromMap(Map map,String key){
        Object object = map.get(key);
        if (object == null){
            //优先返回默认
            String kk = fromToChangeDefaultMap.get(key);
            if (kk != null){
                return "'"+kk.replace("'","''")+"'";
            }
            return "null";
        }
        if (object instanceof Date){
            return "'"+DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,(Date) object)+"'";
        }else{
            String value = "null";
            String iKey;
            if (object instanceof String){
                value = "'"+((String) object).replace("'","''")+"'";
                iKey = (String) object;
            }else {
                value = object.toString();
                iKey = object.toString();
            }
            if (fromToChangeMap == null){
                return value;
            }            //值转换
            Map map1 = fromToChangeMap.get(key);
            if (map1 != null){
                Object ob = map1.get(iKey);
                if (ob != null){
                    if (ob instanceof Date){
                        return "'"+DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,(Date) ob)+"'";
                    }else {
                        if (ob instanceof String){
                            value = "'"+((String) ob).replace("'","''")+"'";
                        }else {
                            value = ob.toString();
                        }
                    }
                }else {
                    //优先返回默认
                    String kk = fromToChangeDefaultMap.get(key);
                    if (kk != null){
                        value = "'"+kk.replace("'","''")+"'";
                    }
                }
            }
            return value;
        }
    }


    public enum SyncModelType {
        TypeString,TypeInteger,TypeDouble,TypeFloat,TypeDate;
    }

    /**
     *
     *           Demo
     *
     *
     *             SyncModel syncModel = new SyncModel();
     *             syncModel.setService(null,toIService);
     *             syncModel.setTable("ComputationUnit","md_unit_measure");
     *             syncModel.setSyncData("cComunitCode","CONVERT(BIGINT,pubufts)","cComunitCode","pubufts");
     *             syncModel.addColumn("cComunitCode","cComunitCode", SyncModel.SyncModelType.TypeString);
     *             syncModel.addColumn("cComUnitName","cComUnitName", SyncModel.SyncModelType.TypeString);
     *             syncModel.addColumn("cGroupCode","cGroupCode", SyncModel.SyncModelType.TypeString);
     *             syncModel.addColumn("cBarCode","cBarCode", SyncModel.SyncModelType.TypeString);
     *             syncModel.addColumn("bMainUnit","bMainUnit", SyncModel.SyncModelType.TypeInteger);
     *             syncModel.addColumn("iChangRate","iChangRate", SyncModel.SyncModelType.TypeFloat);
     *             syncModel.addColumn("CONVERT(BIGINT,pubufts)","pubufts", SyncModel.SyncModelType.TypeInteger);
     *             syncModel.synsStart();
     *
     *
     */





}
